package stutter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * The Class Stutter. Identify the instances of a stutter in a text file or 
 * keyboard input (duplicate word)
 * 
 * @author dustin carroll
 */
public class Stutter
{
  private BufferedReader _inputFile;
  
  /**
   * Instantiates a new stutter.
   */
  private Stutter() 
  {
	  
  }
  
  /**
   * Instantiates a new stutter.
   * 
   * Method of using StringReader to populate a BufferedReader found here:
   * 	http://www.codingdiary.com/developers/developers/diary/javaapi/java/io
   * 		/SampleCode/BufferedReaderread1ExampleCode.html
   */
  public Stutter(String inputString) 
  {
      StringReader stringReader = new StringReader(inputString);
      _inputFile = new BufferedReader(stringReader);
  }

  /**
   * Identify the word and line number when there is a duplicate word.
   * Ex. the the
   * 
   */
  public String identifyStutter()
  {
    int lineCount = 1;
    int currentCharacter;
    boolean lineDelimiter = true;
    StringBuffer output = new StringBuffer();

    List<Character> currentWord = new ArrayList<Character>();
    List<Character> previousWord = new ArrayList<Character>();

    /* 
     * If a file has a read error, the user will be alerted and the entire file
     * will be skipped
     */
    try {
      for (currentCharacter = _inputFile.read(); currentCharacter != -1; 
           currentCharacter = _inputFile.read()) {

        if (testForNonWordCharacter((char) currentCharacter)) {

          /* 
           * This if condition tests whether there are multiple non-word
           * characters. If there is more than one non-word character
           * loop until there is a word character
           */ 
          if (!lineDelimiter) { 
            lineDelimiter = true;
            currentWord.add('\0');

            /*
             * If there is a duplicate word, output the word and line count to
             * the screen, otherwise copy the current word into the previous
             * word and continue processing
             */
            if (testForEquivalentStrings(currentWord, previousWord)) {
            	output.append(outputRepeatedWord(currentWord, lineCount));
            	output.append("<br>");
            }
            else {
              copyString(currentWord, previousWord);
            }
            currentWord.clear();
          }
          
          if (currentCharacter == '\n') {
              ++lineCount;
              previousWord.clear();
          }
        }
        else {
          //
          lineDelimiter = false;
          currentWord.add((char) currentCharacter);
        }
      }
      
      /* 
       * The very last character is not included in the loop so there is no 
       * comparison of the very last two words. Moving this in order to 
       * accommodate for this case
       */
      currentWord.add('\0');

      if (testForEquivalentStrings(currentWord, previousWord)) {
    	  output.append(outputRepeatedWord(currentWord, lineCount));
      }
    }
    catch (IOException e) {
      System.out.println("Skipping file: Problem reading from input file.");
    }
    
    return output.toString();
  }
  
  private String outputRepeatedWord (List<Character> characterList, int integer) {
	  StringBuffer outputString = new StringBuffer(); 
	  outputString.append("Repeated word on line ")
	  	.append(integer)
	  	.append(": ")
	  	.append(convertCharacterListToString(characterList));
	  	
	  return outputString.toString();
  }

  /**
   * Test if the character is a non-word character and should be ignored.
   *
   * @param character the character argument
   * @return true, if the character is in the ignored characters list
   */
  public boolean testForNonWordCharacter(char character)
  {
    List<Character> ignoredCharactersList = Arrays.asList('\0', '\n', ' ', ' ',
        ',', '.', '!', '-', '+', '=', ';', ':', '?', '&', '{', '}', '\\');

    if (ignoredCharactersList.contains(character))
      return true;

    return false;
  }

  /**
   * Test that the character lists contain equivalent strings.
   *
   * @param characterListOne the first word
   * @param characterListTwo the second word
   * @return true, if the string values are equal
   */
  public boolean testForEquivalentStrings(List<Character> characterListOne,
      List<Character> characterListTwo)
  {
    int currentLetterPosition = 0;

    if (characterListOne.isEmpty() || characterListTwo.isEmpty())
      return false;

    while ((characterListOne.get(currentLetterPosition) != '\0') && 
        (characterListTwo.get(currentLetterPosition) != '\0')) {

    	Character characterOne = characterListOne.get(currentLetterPosition);
    	Character characterTwo = characterListTwo.get(currentLetterPosition);
    	
    	if (Character.toLowerCase(characterOne) != 
    		Character.toLowerCase(characterTwo)) {
    		return false;
    	}
      
      currentLetterPosition++;
    }

    if ((characterListOne.get(currentLetterPosition) == '\0') && 
        (characterListTwo.get(currentLetterPosition) == '\0'))
      return true;

    return false;
  }

  /**
   * Copy the string value from one character list to another.
   *
   * @param sourceCharacterList the source word
   * @param destinationCharacterList the destination word
   */
  public void copyString(List<Character> sourceCharacterList,
      List<Character> destinationCharacterList)
  {
    destinationCharacterList.clear();

    for (char letter : sourceCharacterList) {
      destinationCharacterList.add(letter);
    }
  }

  /**
   * Method to output a string containing the value of a character list 
   * argument.
   *
   * @param characterList the character list to be converted
   * @return a string created from the character list value
   */
  public String convertCharacterListToString(List<Character> characterList)
  {
    StringBuffer outputString = new StringBuffer();

    for (Character character : characterList) {
      if (character != '\0') {
    	  character = Character.toLowerCase(character);
    	  outputString.append(character);
      }
    }

    return outputString.toString();
  }
}
